package com.yjw.rpc.v1;

import com.yjw.rpc.IoUtils;
import com.yjw.rpc.RpcRequest;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Map;

/**
 * @author: James Yin
 * @description:
 * @date: 2/10/2020 10:08 PM
 */
public class ProcessHandler implements Runnable {

    private Socket socket;
    private Map<String, Object> services;

    public ProcessHandler(Socket socket, Map<String, Object> services) {
        this.socket = socket;
        this.services = services;
    }

    @Override
    public void run() {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        try {
            ois = new ObjectInputStream(socket.getInputStream());
            // 处理请求参数，反射调用服务方法
            RpcRequest rpcRequest = (RpcRequest) ois.readObject();
            Object result = invoke(rpcRequest);
            oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IoUtils.close(oos, ois);
        }
    }

    /**
     * 反射调用服务方法，返回执行结果
     *
     * @param rpcRequest
     */
    private Object invoke(RpcRequest rpcRequest) throws NoSuchMethodException,
            InvocationTargetException, IllegalAccessException {
        String className = rpcRequest.getClassName();
        Object service = services.get(className);
        if (service == null) {
            throw new RuntimeException("service is null");
        }
        Class clzss = service.getClass();
        Object[] parameters = rpcRequest.getParameters();
        Class<?>[] parameterTypes = new Class[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            parameterTypes[i] = parameters[i].getClass();
        }
        Method method = clzss.getMethod(rpcRequest.getMethodName(), parameterTypes);
        Object result = method.invoke(service, parameters);
        return result;
    }
}
